package com.chezai.client.server;

import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;

import com.chezai.client.bean.TerminalBaseInfo;
import com.chezai.client.bean.TerminalParameter;
import com.chezai.client.dao.manager.TerminalBaseInfoDaoManager;
import com.chezai.client.dao.manager.TerminalParameterDaoManager;
import com.chezai.client.global.Const;
import com.chezai.client.global.LogService;
import com.chezai.client.global.NetConst;
import com.chezai.client.global.TerminalApplication;
import com.chezai.client.server.codec.NettyChannelHandlerAdapter;
import com.chezai.client.server.codec.NettyTerminalBodyCodec;
import com.chezai.client.server.codec.NettyTerminalHeadCodec;
import com.chezai.client.server.util.PassUtil;
import com.chezai.client.utils.AESUtil;
import com.chezai.client.utils.PreferenceManager;
import com.chezai.client.utils.ToastUtil;
import com.jx.driving.request.Terminal0x0002Request;
import com.jx.driving.request.Terminal0x0102Request;
import com.jx.driving.util.PassUtils;
import com.orhanobut.logger.Logger;

import java.security.PrivateKey;
import java.util.Arrays;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import io.netty.channel.ChannelHandler;
import io.netty.util.AttributeKey;


/**
 * Created by likunyang on 2017/8/24.
 */

public class TerminalSocketClientManager extends NettySocketClient {
    private static TerminalSocketClientManager newInstance;
    private String TAG = this.getClass().getSimpleName();
    private String phone ;
    private Timer mHeartTimer;
    private TimerTask mHeartTask;
    private long mTimeoutGap = 60;//超时时间
    private long mHeartTimeGap = 10;//心跳间隔时间
    private boolean isAuthenticated;
    private boolean isStartTimer;//定时任务是否开始
    private Timer mTimeoutTimer;
    private TimerTask mTimeoutTimerTask;
    private boolean isStartTimeOutTimer;
    private Timer changeServerTimer;

    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == Const.CHANNEL_INACTIVE) {
                ToastUtil.showToast(TerminalApplication.getTerminalContext(), "正在连接服务器");
            } else if (msg.what == Const.HEADER_JUMP) {
                tellWithNoAuth(new Terminal0x0002Request());
            } else if (msg.what == Const.INIT_SOCKET_CLIENT) {
                initSocketClient();
            }
            return true;
        }
    });

    private TerminalSocketClientManager() {
        initSocketClient();
        initHeartTimer();
//        initTimeoutTimer();
    }

    public static TerminalSocketClientManager getInstance() {
        if (newInstance == null) {
            synchronized (TerminalSocketClientManager.class) {
                if (newInstance == null) {
                    newInstance = new TerminalSocketClientManager();
                }
            }
        }
        return newInstance;
    }

    /**
     * 初始化SockClient
     */
    private void initSocketClient() {
        if (NetConst.RELEASE_SERVER) {
            serverAddress = TerminalParameterDaoManager.getInstance().findTerminalParameterByKeyId(19).getValue();
            serverPort = Integer.parseInt(TerminalParameterDaoManager.getInstance().findTerminalParameterByKeyId(24).getValue());
        } else {
            serverAddress = NetConst.TEST_TCP_ADDRESS;
            serverPort = Integer.parseInt(NetConst.TEST_TCP_PORT);
        }
        phone = TerminalBaseInfoDaoManager.getInstance().getSim();
        setServerAddress(serverAddress);
        setServerPort(serverPort);
        if (isConnect()) {
            close();
        }
        connect();
    }

    /**
     * 初始化超时任务
     */
    private void initTimeoutTimer() {
        TerminalParameter obj = TerminalParameterDaoManager.getInstance().findTerminalParameterByKeyId(2);
        if (null != obj) {
            mTimeoutGap = Long.valueOf(obj.getValue()) * 1000;
        }
        mTimeoutTimer = new Timer(true);
        mTimeoutTimerTask = new TimerTask() {
            @Override
            public void run() {

            }
        };
    }

    /**
     * 停止超时倒计时
     */
    public void stopTimeOutTimer() {
        if (isStartTimeOutTimer) {
            mTimeoutTimer.cancel();
            isStartTimeOutTimer = false;
        }
    }

    /**
     * 开始超时倒计时
     */
    public void startTimeoutTimer() {
        if (!isStartTimeOutTimer) {
            mTimeoutTimer.schedule(mTimeoutTimerTask, mTimeoutGap);
            isStartTimeOutTimer = true;
        }
    }

    /**
     * 初始化心跳任务
     */
    private void initHeartTimer() {
        TerminalParameter obj = TerminalParameterDaoManager.getInstance().findTerminalParameterByKeyId(1);
        if (null != obj) {
            mHeartTimeGap = Long.valueOf(obj.getValue()) * 1000;
        }
        if (mHeartTimer == null) {
            mHeartTimer = new Timer(true);
        }
        if (mHeartTask == null) {
            mHeartTask = new TimerTask() {
                @Override
                public void run() {
                    tellWithNoAuth(new Terminal0x0002Request());
                }
            };
        }
    }

    /**
     * 切换连接服务器地址
     *
     * @param serverAddress  服务器地址
     * @param serverPort     服务器端口号
     * @param connectionTime 连接时长 单位分钟，值非0一直连接制定服务器
     * @param connOrder      0 连接监管，1回复正常
     */
    public void changeServerAddress(String serverAddress, int serverPort, int connectionTime, int connOrder) {
        if (connOrder == Const.ConnectionOrder.CHANGE) {
            if (TextUtils.isEmpty(serverAddress) || serverPort == 0) {
                return;
            }
            if (isConnect()) {
                close();
            }
            setServerAddress(serverAddress);
            setServerPort(serverPort);
            connect();
            if (connectionTime != 0) {
                if (changeServerTimer != null) {
                    changeServerTimer.cancel();
                    changeServerTimer = null;
                }
                changeServerTimer = new Timer(true);
                TimerTask timerTask = new TimerTask() {
                    @Override
                    public void run() {
                        mHandler.sendEmptyMessage(Const.INIT_SOCKET_CLIENT);
                        cancel();
                    }
                };
                changeServerTimer.schedule(timerTask, connectionTime * 60 * 1000);
            }
        } else if (connOrder == Const.ConnectionOrder.NORMAL) {
            if (changeServerTimer != null) {
                changeServerTimer.cancel();
                changeServerTimer = null;
            }
            initSocketClient();
        }

    }

    /**
     * 是否鉴权
     *
     * @return true 已鉴权，false 未鉴权
     */
    public boolean isAuthenticated() {
        return isAuthenticated;
    }

    /**
     * 设置是否鉴权
     *
     * @param authenticated 鉴权状态 true/false
     */
    public void setAuthenticated(boolean authenticated) {
        isAuthenticated = authenticated;
    }

    /**
     * 设置心跳时间
     *
     * @param mHeartTimeGap
     */
    public void setmHeartTimeGap(long mHeartTimeGap) {
        this.mHeartTimeGap = mHeartTimeGap;
        if (isStartTimer) {
            stopSendHead();
        }
        startSendHead();
    }

    /**
     * 开始定时发送心跳
     */
    public void startSendHead() {
        if (isStartTimer) {
            return;
        }
        isStartTimer = true;
        initHeartTimer();
        mHeartTimer.schedule(mHeartTask, 0, mHeartTimeGap);
    }

    /**
     * 停止发送心跳包
     */
    public void stopSendHead() {
        if (isStartTimer) {
            mHeartTimer.cancel();
            mHeartTimer = null;
            mHeartTask.cancel();
            mHeartTask = null;
        }
        isStartTimer = false;
    }


    @Override
    protected List<? extends ChannelHandler> channelHandlerList() {
        return Arrays.asList(new NettyTerminalHeadCodec(), new NettyTerminalBodyCodec(),
                new NettyChannelHandlerAdapter(new ChannelListenerImpl()));
    }

    /**
     * 鉴权
     */
    public void authenTicate() {
        Logger.t(TAG).i("鉴权中...");
        TerminalBaseInfo baseInfo = TerminalBaseInfoDaoManager.getInstance().getTerminalBaseInfo();
        Terminal0x0102Request obj = new Terminal0x0102Request();
        long time = System.currentTimeMillis() / 1000;
        try {
            String cert = baseInfo.getCert();
            String certPassword = AESUtil.aesDecrypt(baseInfo.getCertPassword());
            PrivateKey privateKey = new PassUtil().getDevCAInfo(cert, certPassword);
            byte[] signPass = PassUtils.sign(baseInfo.getDevice(), time, privateKey);//放入终端号
            obj.setTime(time);
            obj.setPass(signPass);
            tellWithNoAuth(obj);
        } catch (Exception e) {
            ToastUtil.showToast(TerminalApplication.getTerminalContext(), "签名错误");
            LogService.getInstance(TerminalApplication.getTerminalContext()).sendLog("cert error ! reason:" + e.getMessage());
        }
    }


    public void setPhone() {
        if (TextUtils.isEmpty(phone)){
            phone = TerminalBaseInfoDaoManager.getInstance().getSim();
        }
        if (channel != null && !TextUtils.isEmpty(phone)) {
            channel.attr(AttributeKey.valueOf("TERMINAL_PHONE")).set(phone);
        }
    }

    public void tellAndSync(Object msg) {
        try {
            if (!status.get()) {
                LogService.getInstance(TerminalApplication.mContext).sendMsg(msg.toString() + "未连接到服务器");
                connect();
                mHandler.sendEmptyMessage(Const.CHANNEL_INACTIVE);
                throw new RuntimeException("未连接到服务器");
            }
            if (isAuthenticated()) {
                setPhone();
                LogService.getInstance(TerminalApplication.mContext).sendMsg(msg);
                channel.writeAndFlush(msg).await();
            } else {
                //终端鉴权
                LogService.getInstance(TerminalApplication.mContext).sendMsg(msg.toString() + "终端未鉴权");
                if (PreferenceManager.isRegister()) {
                    authenTicate();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 不需要验证鉴权
     *
     * @param msg
     */
    public void tellWithNoAuth(Object msg) {
        tell(msg, false);
    }

    /**
     * 需要鉴权
     *
     * @param msg 协议
     */
    public void tellWithNeedAuth(Object msg) {
        tell(msg, true);
    }

    /**
     * @param msg        协议
     * @param isNeedAuth 是否需要鉴权 true 需要，false 不需要
     */
    public void tell(Object msg, boolean isNeedAuth) {
        Logger.t("Request").d(msg);
        try {
            if (!status.get()) {
                connect();
                mHandler.sendEmptyMessage(Const.CHANNEL_INACTIVE);
                throw new RuntimeException("未连接到服务器");
            }
            if (isNeedAuth) {
                if (isAuthenticated()) {
                    channelWrite(msg);
                } else {
                    //终端鉴权
                    if (PreferenceManager.isRegister()) {
                        authenTicate();
                    }
                }
            } else {
                channelWrite(msg);
            }
        } catch (RuntimeException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void channelWrite(Object msg) {
        setPhone();
        channel.write(msg);
        channel.flush();
        LogService.getInstance(TerminalApplication.mContext).sendMsg(msg);
    }
}
